package com.atguigu.gmall.seckill.Listener.mq;

import java.math.BigDecimal;

import com.atguigu.gmall.common.constants.RedisConst;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.seckill.biz.LocalCache;
import com.google.common.collect.Lists;

import java.util.Arrays;
import java.util.Collections;
import java.util.Date;

import com.atguigu.gmall.model.activity.CouponInfo;

import com.atguigu.gmall.common.constants.RabbitMqConst;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.JsonUtil;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.model.to.SecKillQueueTo;
import com.atguigu.gmall.seckill.service.SeckillGoodsService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * @author A
 * @version 1.0
 * @description: 监听排队成功扣库存
 * @date 2024/10/20 7:19
 */
@Slf4j
@Component
public class SecKillStockListener {
    @Autowired
    SeckillGoodsService seckillGoodsService;
    @Autowired
    LocalCache localCache;
    @Autowired
    StringRedisTemplate redisTemplate;
    @RabbitListener(bindings = @QueueBinding(value = @Queue(name = RabbitMqConst.QUEUE_SECKILL_STOCK, durable = "true", autoDelete = "false")
            , exchange = @Exchange(name = RabbitMqConst.SECKILL_EVENT_EXCHANGE, type = "topic", durable = "true", autoDelete = "false")
            , key = RabbitMqConst.SECKILL_RK_STOCK))
    public void reduceSecKillStock(Message message, Channel channel) {
        String json = new String(message.getBody());
        SecKillQueueTo secKillQueueTo = JsonUtil.json2Obj(json, new TypeReference<SecKillQueueTo>() {
        });
        try {

            log.info("排队成功:{}", secKillQueueTo);
            // 修改数据库库存
            // 生成秒杀单
            reduceSecKillStockAndSaveTempOrder(secKillQueueTo);
        } catch (Exception e) {
            //修改库存失败

            String tempKey= RedisConst.SECKILL_TEMP_ORDER_PREFIX+secKillQueueTo.getUserId()+":"+secKillQueueTo.getDateStr()+":"+secKillQueueTo.getSkuId();
            redisTemplate.opsForValue().set(tempKey,"boom",1, TimeUnit.DAYS);

            throw e;
        }


        try {

            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            log.error("扣库存失败消息消费失败:{}", e);
        }
    }

    @Transactional
    public void reduceSecKillStockAndSaveTempOrder(SecKillQueueTo secKillQueueTo) {
        //库存减1
        seckillGoodsService.reduceStock(secKillQueueTo.getSkuId());
        //redis保存临时订单
        OrderInfo orderInfo = preparOrderInfo(secKillQueueTo);
        String tempKey= RedisConst.SECKILL_TEMP_ORDER_PREFIX+secKillQueueTo.getUserId()+":"+secKillQueueTo.getDateStr()+":"+secKillQueueTo.getSkuId();
        redisTemplate.opsForValue().set(tempKey,JsonUtil.obj2Json(orderInfo),1, TimeUnit.DAYS);


    }

    private OrderInfo preparOrderInfo(SecKillQueueTo secKillQueueTo) {
        Long skuId = secKillQueueTo.getSkuId();
        Long userId = secKillQueueTo.getUserId();
        String code = secKillQueueTo.getCode();
        SeckillGoods detail = localCache.getSeckillGoodsDetail(skuId);
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setTotalAmount(detail.getCostPrice());
        ProcessStatus unpaid = ProcessStatus.UNPAID;
        orderInfo.setOrderStatus(unpaid.getOrderStatus().name());
        orderInfo.setUserId(userId);
        orderInfo.setPaymentWay("2");
        orderInfo.setTradeBody(detail.getSkuName());
        orderInfo.setCreateTime(new Date());
        long min30 = System.currentTimeMillis() + 1000 * 60 * 30;
        orderInfo.setExpireTime(new Date(min30));
        orderInfo.setProcessStatus(unpaid.name());
        orderInfo.setParentOrderId(0L);
        orderInfo.setImgUrl(detail.getSkuDefaultImg());
        //造好详情
        OrderDetail orderDetail=buildOrderDetail(detail,secKillQueueTo);
        orderInfo.setOrderDetailList(Collections.singletonList(orderDetail));


        orderInfo.setOriginalTotalAmount(detail.getPrice());
        orderInfo.setOperateTime(new Date());

        return orderInfo;
    }

    private OrderDetail buildOrderDetail(SeckillGoods detail, SecKillQueueTo secKillQueueTo) {
        OrderDetail orderDetail = new OrderDetail();

        orderDetail.setUserId(secKillQueueTo.getUserId());
        orderDetail.setSkuId(secKillQueueTo.getSkuId());
        orderDetail.setSkuName(detail.getSkuName());
        orderDetail.setImgUrl(detail.getSkuDefaultImg());
        orderDetail.setOrderPrice(detail.getCostPrice());
        orderDetail.setSkuNum(1);
        orderDetail.setCreateTime(new Date());
        orderDetail.setSplitTotalAmount(detail.getCostPrice());


        return orderDetail;

    }
}


